babl: speed up trc dispatch
authorØyvind Kolås <pippin@gimp.org>
Wed, 30 Aug 2017 15:09:28 +0000 (17:09 +0200)
committerØyvind Kolås <pippin@gimp.org>
Wed, 30 Aug 2017 15:09:31 +0000 (17:09 +0200)
By splitting the core computation done by the TRC down to callbacks of
different types, that all optionally can use the provided trc object.  This way
we can move the conditional for the polymorphism out of loops. The higher level
API of using the TRC still works - and is also accelerated by this change.

babl/babl-fish-path.c
babl/babl-fish.c
babl/babl-trc.c
babl/babl-trc.h

index 4ac50161a1cec93220dfa54350198aab6811c7d3..f89aae108993fb9d4743d73e2f498bc1848fc9af 100644 (file)
@@ -283,14 +283,11 @@ _babl_fish_path_destroy (void *data)
   return 0;
 }
 
-BablList *accum = NULL;
-
 static int
 show_item (Babl *babl,
            void *user_data)
 {
   BablConversion *conv = (void *)babl;
-  //BablSpace *space = user_data;
 
   if (conv->destination->class_type == BABL_FORMAT)
   {
@@ -413,14 +410,27 @@ alias_conversion (Babl *babl,
 static void prep_conversion (const Babl *babl)
 {
   Babl *conversion = (void*) babl;
-  float *matrixf = babl_calloc (sizeof (float), 9); // we leak this matrix , which is a singleton
+  const Babl *source_space = babl_conversion_get_source_space (conversion);
+  float *matrixf;
+  int i;
+  float *lut;
+
   double matrix[9];
   babl_matrix_mul_matrix (
      (conversion->conversion.destination)->format.space->space.XYZtoRGB,
      (conversion->conversion.source)->format.space->space.RGBtoXYZ,
      matrix);
+
+  matrixf = babl_calloc (sizeof (float), 9 + 256); // we leak this matrix , which is a singleton
   babl_matrix_to_float (matrix, matrixf);
   conversion->conversion.data = matrixf;
+
+  lut = matrixf + 9;
+  for (i = 0; i < 256; i++)
+  {
+    lut[i] = _babl_trc_to_linear (source_space->space.trc[0], i/255.0);
+    // XXX: should have green and blue luts as well
+  }
 }
 
 static inline long
@@ -429,6 +439,19 @@ universal_nonlinear_rgb_converter (const Babl *conversion,unsigned char *src_cha
   const Babl *source_space = babl_conversion_get_source_space (conversion);
   const Babl *destination_space = babl_conversion_get_destination_space (conversion);
 
+  void   *to_trc_red;
+  void   *to_trc_green;
+  void   *to_trc_blue;
+  float (*to_linear_red) (void *trc, float value);
+  float (*to_linear_green) (void *trc, float value);
+  float (*to_linear_blue) (void *trc, float value);
+  void   *from_trc_red;
+  void   *from_trc_green;
+  void   *from_trc_blue;
+  float (*from_linear_red) (void *trc, float value);
+  float (*from_linear_green) (void *trc, float value);
+  float (*from_linear_blue) (void *trc, float value);
+
   float * matrixf = conversion->conversion.data;
   int i;
   float *rgba_in = (void*)src_char;
@@ -436,17 +459,34 @@ universal_nonlinear_rgb_converter (const Babl *conversion,unsigned char *src_cha
   assert (source_space);
   assert (destination_space);
 
+  to_linear_red   = (void*)source_space->space.trc[0]->trc.fun_to_linear;
+  to_trc_red      = (void*)source_space->space.trc[0];
+  from_linear_red = (void*)destination_space->space.trc[0]->trc.fun_from_linear;
+  from_trc_red    = (void*)destination_space->space.trc[0];
+
+  to_linear_green = (void*)source_space->space.trc[1]->trc.fun_to_linear;
+  to_trc_green    = (void*)source_space->space.trc[1];
+  from_linear_green= (void*)destination_space->space.trc[1]->trc.fun_from_linear;
+  from_trc_green  = (void*)destination_space->space.trc[1];
+
+  to_linear_blue  = (void*)source_space->space.trc[2]->trc.fun_to_linear;
+  to_trc_blue     = (void*)source_space->space.trc[2];
+  from_linear_blue= (void*)destination_space->space.trc[2]->trc.fun_from_linear;
+  from_trc_blue   = (void*)destination_space->space.trc[2];
+
   for (i = 0; i < samples; i++)
   {
     float rgba_tmp[4];
-    int c;
-    for (c = 0; c < 3; c ++)
-      rgba_tmp[c] = _babl_trc_to_linear (source_space->space.trc[c], rgba_in[c]);
-    babl_matrix_mul_vectorff (matrixf, rgba_tmp, rgba_out);
 
-    for (c = 0; c < 3; c ++)
-      rgba_out[c] = _babl_trc_from_linear (destination_space->space.trc[c], rgba_out[c]);
+    rgba_tmp[0] = to_linear_red(to_trc_red, rgba_in[0]);
+    rgba_tmp[1] = to_linear_green(to_trc_green, rgba_in[1]);
+    rgba_tmp[2] = to_linear_blue(to_trc_blue, rgba_in[2]);
+
+    babl_matrix_mul_vectorff (matrixf, rgba_tmp, rgba_out);
 
+    rgba_out[0] = from_linear_red(from_trc_red, rgba_out[0]);
+    rgba_out[1] = from_linear_green(from_trc_green, rgba_out[1]);
+    rgba_out[2] = from_linear_blue(from_trc_blue, rgba_out[2]);
     rgba_out[3] = rgba_in[3];
     rgba_in  += 4;
     rgba_out += 4;
@@ -455,36 +495,53 @@ universal_nonlinear_rgb_converter (const Babl *conversion,unsigned char *src_cha
   return samples;
 }
 
-#if 0
+#if 1
 // does not seem to be valid
 static inline long
 universal_nonlinear_rgba_u8_converter (const Babl *conversion,unsigned char *src_char, unsigned char *dst_char, long samples)
 {
-  const Babl *source_space = babl_conversion_get_source_space (conversion);
-  const Babl *destination_space = babl_conversion_get_destination_space (conversion);
+  const Babl *destination_space = conversion->conversion.destination->format.space;
 
   float * matrixf = conversion->conversion.data;
+  float * in_trc_lut = matrixf + 9;
   int i;
   uint8_t *rgba_in_u8 = (void*)src_char;
   uint8_t *rgba_out_u8 = (void*)dst_char;
 
-  assert (source_space);
-  assert (destination_space);
+  void   *from_trc_red;
+  void   *from_trc_green;
+  void   *from_trc_blue;
+  float (*from_linear_red) (void *trc, float value);
+  float (*from_linear_green) (void *trc, float value);
+  float (*from_linear_blue) (void *trc, float value);
+
+  from_linear_red = (void*)destination_space->space.trc[0]->trc.fun_from_linear;
+  from_trc_red    = (void*)destination_space->space.trc[0];
+  from_linear_green= (void*)destination_space->space.trc[1]->trc.fun_from_linear;
+  from_trc_green  = (void*)destination_space->space.trc[1];
+  from_linear_blue= (void*)destination_space->space.trc[2]->trc.fun_from_linear;
+  from_trc_blue   = (void*)destination_space->space.trc[2];
 
   for (i = 0; i < samples; i++)
   {
-    float rgba_tmp[4];
-    float rgba_out[4];
+    float rgb[3];
     int c;
     for (c = 0; c < 3; c ++)
-      rgba_tmp[c] = _babl_trc_to_linear (source_space->space.trc[c], rgba_in_u8[c]/255.0);
+      rgb[c] = in_trc_lut[rgba_in_u8[c]]; 
 
-    babl_matrix_mul_vectorff (matrixf, rgba_tmp, rgba_out);
+    babl_matrix_mul_vectorff (matrixf, rgb, rgb);
 
-    for (c = 0; c < 3; c ++)
     {
-      int v = _babl_trc_from_linear (destination_space->space.trc[c], rgba_out[c]) * 255.5;
-      rgba_out_u8[c] = v < 0 ?  0 : v > 255 ? 255 : v;
+      int v = from_linear_red (from_trc_red, rgb[0]) * 255.5;
+      rgba_out_u8[0] = v; //v < 0 ?  0 : v > 255 ? 255 : v;
+    }
+    {
+      int v = from_linear_green (from_trc_green, rgb[1]) * 255.5;
+      rgba_out_u8[1] = v; //v < 0 ?  0 : v > 255 ? 255 : v;
+    }
+    {
+      int v = from_linear_blue (from_trc_blue , rgb[2]) * 255.5;
+      rgba_out_u8[2] = v; //v < 0 ?  0 : v > 255 ? 255 : v;
     }
 
     rgba_out_u8[3] = rgba_in_u8[3];
@@ -515,43 +572,6 @@ universal_rgb_converter (const Babl *conversion,unsigned char *src_char, unsigne
   return samples;
 }
 
-#if 0
-static inline long
-universal_rgb_converter_u16 (const Babl *conversion,unsigned char *src_char, unsigned char *dst_char, long samples)
-{
-  double matrix[9];
-  float matrixf[9];
-  int i;
-  float rgba_inf[4];
-  float rgba_outf[4];
-  uint16_t *rgba_in = (void*)src_char;
-  uint16_t *rgba_out = (void*)dst_char;
-
-  babl_matrix_mul_matrix (
-     (conversion->conversion.destination)->format.space->space.XYZtoRGB,
-     (conversion->conversion.source)->format.space->space.RGBtoXYZ,
-     matrix);
-  /* XXX: this floating point matrix could be cached, avoiding the overhead of double precision matrix multiplication
-   *      for short spans
-   */
-  babl_matrix_to_float (matrix, matrixf);
-
-  for (i = 0; i < samples; i++)
-  {
-    int c;
-    for (c = 0; c < 4; c ++)
-      rgba_inf[c] = rgba_in[c] / 65535.0;
-    babl_matrix_mul_vectorff (matrixf, rgba_inf, rgba_outf);
-    for (c = 0; c < 4; c ++)
-      rgba_out[c] = rgba_outf[c] * 65535.5;
-    rgba_in  += 4;
-    rgba_out += 4;
-  }
-
-  return samples;
-}
-#endif
-
 static int
 add_rgb_adapter (Babl *babl,
                  void *space)
@@ -575,7 +595,6 @@ add_rgb_adapter (Babl *babl,
                         babl_format_with_space("R'G'B'A float", space),
                         "linear", universal_nonlinear_rgb_converter,
                         NULL));
-#if 0
     prep_conversion(babl_conversion_new(babl_format_with_space("R'G'B'A u8", space),
                         babl_format_with_space("R'G'B'A u8", babl),
                         "linear", universal_nonlinear_rgba_u8_converter,
@@ -584,7 +603,6 @@ add_rgb_adapter (Babl *babl,
                         babl_format_with_space("R'G'B'A u8", space),
                         "linear", universal_nonlinear_rgba_u8_converter,
                         NULL));
-#endif
   }
   return 0;
 }
@@ -648,7 +666,7 @@ babl_fish_path (const Babl *source,
 
     if (!done)
     {
-      if(0)babl_conversion_class_for_each (show_item, (void*)source->format.space);
+      if(1)babl_conversion_class_for_each (show_item, (void*)source->format.space);
       //babl_format_class_for_each (show_fmt, NULL);
       //babl_model_class_for_each (show_fmt, NULL);
     }
index 587c54973ab8cded3d54e1e2832b07a4b3990c12..6e22f899b9a6c8d6d9c35f9e59f2d9720fc992b3 100644 (file)
@@ -169,7 +169,7 @@ babl_fish_get_id (const Babl *source,
   /* value of 'id' will be used as argument for hash function,
    * substraction serves as simple combination of
    * source/destination values. */
-  int id = (((int)source * 93)) ^ ((int)destination);
+  int id = (((size_t)source * 93)) ^ ((size_t)destination);
   /* instances with id 0 won't be inserted into database */
   id *= ((((size_t)  (destination))) % 37);
 
index f63a98477bbbc9f69a638ef24d35a194ba558d19..cabd64d10ad23fbd7a34a3b78d61bb671917a3fd 100644 (file)
@@ -98,9 +98,27 @@ babl_trc_new (const char *name,
     for (j = 0; j < n_lut; j++)
       trc_db[i].inv_lut[j] =
         babl_trc_to_linear (BABL(&trc_db[i]), trc_db[i].lut[(int) ( j/(n_lut-1.0) * (n_lut-1))]);
-    
   }
+
+  switch (trc_db[i].type)
+  {
+    case BABL_TRC_LINEAR:
+      trc_db[i].fun_to_linear = _babl_trc_linearf;
+      trc_db[i].fun_from_linear = _babl_trc_linearf;
+      break;
+    case BABL_TRC_GAMMA:
+      trc_db[i].fun_to_linear = _babl_trc_gamma_to_linearf;
+      trc_db[i].fun_from_linear = _babl_trc_gamma_from_linearf;
+      break;
+    case BABL_TRC_SRGB:
+      trc_db[i].fun_to_linear = _babl_trc_srgb_to_linearf;
+      trc_db[i].fun_from_linear = _babl_trc_srgb_from_linearf;
+      break;
+    case BABL_TRC_LUT:
+      trc_db[i].fun_to_linear = babl_trc_lut_to_linearf;
+      trc_db[i].fun_from_linear = babl_trc_lut_from_linearf;
+      break;
+  }
   return (Babl*)&trc_db[i];
 }
 
index abdf52a9520c67f764da7e3626e3d26a98671ea0..3f36dac44f98f1ce69a46a8d14e1275fbb5185dd 100644 (file)
@@ -39,8 +39,35 @@ typedef struct
   char             name[128];
   float           *lut;
   float           *inv_lut;
+  float          (*fun_to_linear)(const Babl *trc_, float val);
+  float          (*fun_from_linear)(const Babl *trc_, float val);
 } BablTRC;
 
+
+static inline float babl_trc_lut_from_linearf (const Babl *trc_, float value)
+{
+  BablTRC *trc = (void*)trc_;
+  int entry = value * trc->lut_size + 0.5;
+  float ret = trc->inv_lut[
+    (entry >= 0 && entry < trc->lut_size) ?
+                               entry :
+                               trc->lut_size-1];
+  /* XXX: fixme, do linear interpolation */
+  return ret;
+}
+
+static inline float babl_trc_lut_to_linearf (const Babl *trc_, float value)
+{
+  BablTRC *trc = (void*)trc_;
+  int entry = value * trc->lut_size + 0.5;
+  float ret = trc->lut[
+    (entry >= 0 && entry < trc->lut_size) ?
+                               entry :
+                               trc->lut_size-1];
+  /* XXX: fixme, do linear interpolation */
+  return ret;
+}
+
 static inline double babl_trc_lut_from_linear (const Babl *trc_, double value)
 {
   BablTRC *trc = (void*)trc_;
@@ -70,14 +97,10 @@ static inline double _babl_trc_from_linear (const Babl *trc_, double value)
   BablTRC *trc = (void*)trc_;
   switch (trc->type)
   {
-    case BABL_TRC_LINEAR:
-            return value;
-    case BABL_TRC_GAMMA:
-            return pow (value, 1.0/trc->gamma);
-    case BABL_TRC_SRGB:
-            return babl_linear_to_gamma_2_2 (value);
-    case BABL_TRC_LUT:
-            return babl_trc_lut_from_linear (trc_, value);
+    case BABL_TRC_LINEAR: return value;
+    case BABL_TRC_GAMMA:  return pow (value, 1.0/trc->gamma);
+    case BABL_TRC_SRGB:   return babl_linear_to_gamma_2_2 (value);
+    case BABL_TRC_LUT:    return babl_trc_lut_from_linear (trc_, value);
   }
   return value;
 }
@@ -87,42 +110,51 @@ static inline double _babl_trc_to_linear (const Babl *trc_, double value)
   BablTRC *trc = (void*)trc_;
   switch (trc->type)
   {
-    case BABL_TRC_LINEAR:
-            return value;
-    case BABL_TRC_GAMMA:
-            return pow (value, trc->gamma);
-    case BABL_TRC_SRGB:
-            return babl_gamma_2_2_to_linear (value);
-    case BABL_TRC_LUT:
-            return babl_trc_lut_to_linear (trc_, value);
+    case BABL_TRC_LINEAR: return value;
+    case BABL_TRC_GAMMA:  return pow (value, trc->gamma);
+    case BABL_TRC_SRGB:   return babl_gamma_2_2_to_linear (value);
+    case BABL_TRC_LUT:    return babl_trc_lut_to_linear (trc_, value);
   }
   return value;
 }
 
+static inline float _babl_trc_linearf (const Babl *trc_, float value)
+{
+  return 1.0;
+}
+
+static inline float _babl_trc_gamma_to_linearf (const Babl *trc_, float value)
+{
+  BablTRC *trc = (void*)trc_;
+  return powf (value, trc->gamma);
+}
+
+static inline float _babl_trc_gamma_from_linearf (const Babl *trc_, float value)
+{
+  BablTRC *trc = (void*)trc_;
+  return powf (value, 1.0f/trc->gamma);
+}
+
+static inline float _babl_trc_srgb_to_linearf (const Babl *trc_, float value)
+{
+  return babl_gamma_2_2_to_linearf (value);
+}
+
+static inline float _babl_trc_srgb_from_linearf (const Babl *trc_, float value)
+{
+  return babl_linear_to_gamma_2_2f (value);
+}
+
 static inline float _babl_trc_from_linearf (const Babl *trc_, float value)
 {
   BablTRC *trc = (void*)trc_;
-  switch (trc->type)
-  {
-    case BABL_TRC_LINEAR: return value;
-    case BABL_TRC_GAMMA:  return powf (value, 1.0f/trc->gamma);
-    case BABL_TRC_SRGB:   return babl_linear_to_gamma_2_2f (value);
-    case BABL_TRC_LUT:    return babl_trc_lut_from_linear (trc_, value);
-  }
-  return value;
+  return trc->fun_from_linear (trc_, value);
 }
 
 static inline float _babl_trc_to_linearf (const Babl *trc_, float value)
 {
   BablTRC *trc = (void*)trc_;
-  switch (trc->type)
-  {
-    case BABL_TRC_LINEAR: return value;
-    case BABL_TRC_GAMMA:  return powf (value, trc->gamma);
-    case BABL_TRC_SRGB:   return babl_gamma_2_2_to_linearf (value);
-    case BABL_TRC_LUT:    return babl_trc_lut_to_linear (trc_, value);
-  }
-  return value;
+  return trc->fun_to_linear (trc_, value);
 }
 
 void